package com.xx.bysj.service.imp;

import cn.hutool.bloomfilter.BloomFilter;
import cn.hutool.bloomfilter.BloomFilterUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.xx.bysj.dto.HnMenu;
import com.xx.bysj.dto.HnUser;
import com.xx.bysj.dto.Menu;
import com.xx.bysj.dto.MenuManageDto;
import com.xx.bysj.mapper.HnMenuMapper;
import com.xx.bysj.mapper.HnUserMapper;
import com.xx.bysj.mapper.MenuMapper;
import com.xx.bysj.service.MenuService;
import com.xx.bysj.utils.MenuResultUtils;
import com.xx.bysj.utils.NumberUtils;
import com.xx.bysj.utils.RedisCacheUtils;
import com.xx.bysj.utils.RedisConstants;
import com.xx.bysj.utils.Result;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import javax.annotation.Resource;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;

/**
 * 导航栏实现类
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class MenuServiceImpl implements MenuService {
    @Autowired
    private HnUserMapper userMapper;

    @Autowired
    private HnMenuMapper menuMapper;

    @Resource
    private RedisCacheUtils redisCacheUtils;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    //布隆过滤器
    private BloomFilter bloomFilter = BloomFilterUtil.createBitMap(1000);

    /**
     * 获取所有的的菜单信息
     * @param user
     * @return
     */
    @Override
    public String showMenu(HnUser user) {
        List<HnUser> userList = userMapper.selectByUserNameList(user);
        if (CollectionUtils.isNotEmpty(userList)) {
            HnUser hnUser = userList.get(0);
            // 查询缓存，如果有缓存就不在查询数据库了，直接用缓存
            return redisCacheUtils.queryWithPassThrough(RedisConstants.MENU_ROLE_CODE_KEY,hnUser.getUserRoleId(),
                    hnUser, String.class, this::getMenu, 30L, TimeUnit.MINUTES);
        }
        return null;
    }

    /**
     * 菜单管理
     * 该段逻辑可以引入redis来优化(后续会引入redis)
     * @return
     */
    @Override
    public MenuResultUtils menuManage() {
        HashMap<String, Object> map = new HashMap<>();
        // 理论上不应该有查全表的SQL
        List<HnMenu> menuAllList = menuMapper.selectAllMenu();
        int count = menuAllList.size();
        List<MenuManageDto> menuManageDtoList = new ArrayList<>();
        for (HnMenu menu : menuAllList) {
            MenuManageDto dto = new MenuManageDto();
            dto.setAuthorityId(menu.getId());
            dto.setAuthorityName(menu.getTitle());
            dto.setOrderNumber(menu.getId());
            dto.setMenuUrl(menu.getHref());
            dto.setMenuIcon(menu.getIcon());
            dto.setCreateTime(menu.getCreateAt());
//            dto.setAuthority(menu.getPerms());
            dto.setChecked(0);
            dto.setUpdateTime(menu.getUpdateAt());
            dto.setIsMenu(menu.getSort());
            dto.setParentId(menu.getPid());
            dto.setStatus(menu.getStatus());
            menuManageDtoList.add(dto);
        }
        map.put("count", count);
        map.put("menuGuanList", menuManageDtoList);
        return new MenuResultUtils((Integer) map.get("count"), map.get("menuGuanList"));
    }

    @Override
    public List<HnMenu> queryType() {
        return menuMapper.queryType();
    }

    @Override
    public List<HnMenu> queryNode() {
        List<HnMenu> menuList = menuMapper.queryNode();
        HnMenu menu = new HnMenu();
        menu.setId(-1);
        menu.setTitle("最高级(无父级)");
        menuList.add(menu);
        return menuList;
    }

    @Override
    public Result updateMenu(HnMenu menu,Authentication authentication) {
        Result result = new Result();
        menuMapper.updateByPrimaryKeySelective(menu);
        // 校验权限名称是否有重复
        List<HnMenu> menuList = menuMapper.selectByMenu(menu);
        HnUser user = new HnUser();
        user.setUserName(authentication.getName());
        List<HnUser> userList = userMapper.selectByUserNameList(user);
        if (CollectionUtils.isNotEmpty(menuList)) {
            if (menuList.size() > 1) {
                // 手动回滚事务，不更新数据库
                TransactionAspectSupport.currentTransactionStatus()
                        .setRollbackOnly();
                return Result.fail("权限名称不可重复");
            } else {
                String key = RedisConstants.MENU_ROLE_CODE_KEY + userList.get(0).getUserRoleId();
                stringRedisTemplate.delete(key);
                return Result.success("更新成功");
            }
        }else {
            return Result.fail("更新失败");
        }
    }

    @Override
    public Result addMenu(HnMenu menu, Authentication authentication) {
        menu.setCreateAt(new Date());
        menu.setUpdateAt(new Date());
        menu.setVersionNumber(0);
        HnUser user = new HnUser();
        user.setUserName(authentication.getName());
        List<HnUser> userList = userMapper.selectByUserNameList(user);
        try {
            String key = RedisConstants.MENU_ROLE_CODE_KEY + userList.get(0).getUserRoleId();
            menuMapper.insert(menu);
            stringRedisTemplate.delete(key);
        }catch (Exception e){
            throw e;
        }
        return Result.success("添加成功");
    }

    @Override
    public Result deleteMenu(String title,Authentication authentication) {
        List<HnMenu> menuList = menuMapper.selectByTitle(title);
        HnUser user = new HnUser();
        user.setUserName(authentication.getName());
        List<HnUser> userList = userMapper.selectByUserNameList(user);
        if (CollectionUtils.isNotEmpty(menuList)) {
            String key = RedisConstants.MENU_ROLE_CODE_KEY + userList.get(0).getUserRoleId() ;
            HnMenu menu = menuList.get(0);
            Integer id = menu.getId();
            menuMapper.deleteById(id);
            stringRedisTemplate.delete(key);
            return Result.success("删除成功");
        }else{

            return Result.fail("删除失败，请联系管理员");
        }
    }

    public String getMenu(HnUser hnUser) {
        Map<String, Object> menuMap = new HashMap<>();
        Map<String, String> home = new HashMap<>();
        Map<String, String> logo = new HashMap<>();

        home.put("title", "首页");
        //控制器路由,自行定义
        home.put("href", "/welcome");
        logo.put("title", "管理信息系统");
        //静态资源文件路径,可使用默认的logo.png
        logo.put("image", "/images/logo.png");
        logo.put("href", "/welcome");
        menuMap.put("homeInfo", home);
        menuMap.put("logoInfo", logo);
        // 菜单
        List<HnMenu> menuList = new ArrayList<>();
        menuList = menuMapper.selectByUser(hnUser);
        // 最后返回的list
        List<Menu> resultMenu = new ArrayList<>();
        //第一层menu
        List<HnMenu> firstMenuList = new ArrayList<>();
        //第二层menu
        List<HnMenu> secondMenuList = new ArrayList<>();
        //第三层menu
        List<HnMenu> thirdMenuList = new ArrayList<>();

        // 对查询出来的菜单进行分类
        for (HnMenu menu : menuList) {
            if (menu.getSort().equals(NumberUtils.ZERO)) {
                // -2 为横向菜单为第一层菜单
                firstMenuList.add(menu);
            } else if (menu.getSort().equals(NumberUtils.ONE)) {
                // -1 为纵向菜单为第二层菜单
                secondMenuList.add(menu);
            } else if (menu.getSort().equals(NumberUtils.TWO)) {
                // 0 为纵向菜单细分菜单为第三层菜单
                thirdMenuList.add(menu);
            }
        }

        // 将三层菜单进行关系嵌套
        for (HnMenu firstMenu : firstMenuList) {
            //通过菜单包装类包装好数据后返回给前端
            Menu firstMenus = new Menu();
            firstMenus.setId(firstMenu.getId());
            firstMenus.setPid(firstMenu.getPid());
            firstMenus.setHref(firstMenu.getHref());
            firstMenus.setTitle(firstMenu.getTitle());
            firstMenus.setIcon(firstMenu.getIcon());
            firstMenus.setTarget(firstMenu.getTarget());
            List<Menu> firstMenuChild = new ArrayList<>();
            for (HnMenu secondMenu : secondMenuList) {
                Menu secondMenus = new Menu();
                // 如果二级菜单的父级id为一级菜单的id则绑定
                if (firstMenu.getId().equals(secondMenu.getPid())) {
                    secondMenus.setId(secondMenu.getId());
                    secondMenus.setPid(secondMenu.getPid());
                    secondMenus.setHref(secondMenu.getHref());
                    secondMenus.setTitle(secondMenu.getTitle());
                    secondMenus.setIcon(secondMenu.getIcon());
                    secondMenus.setTarget(secondMenu.getTarget());
                    firstMenuChild.add(secondMenus);
                }
                List<Menu> secondMenuChild = new ArrayList<>();
                for (HnMenu thirdMenu : thirdMenuList) {
                    Menu thirdMenus = new Menu();
                    // 如果三级菜单的父id为二级菜单的id则绑定
                    if (secondMenu.getId().equals(thirdMenu.getPid())) {
                        thirdMenus.setId(thirdMenu.getId());
                        thirdMenus.setPid(thirdMenu.getPid());
                        thirdMenus.setHref(thirdMenu.getHref());
                        thirdMenus.setTitle(thirdMenu.getTitle());
                        thirdMenus.setIcon(thirdMenu.getIcon());
                        thirdMenus.setTarget(thirdMenu.getTarget());
                        secondMenuChild.add(thirdMenus);
                    }
                }
                secondMenus.setChild(secondMenuChild);
            }
            firstMenus.setChild(firstMenuChild);
            resultMenu.add(firstMenus);
        }
        menuMap.put("menuInfo", resultMenu);
        return JSONUtil.toJsonStr(menuMap);
    }
}
